package fw.helpers;

import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fw.ApplicationManager;

public class LinkCheckHelper {

	private final ApplicationManager app;
	private static Logger LOG = LoggerFactory.getLogger(LinkCheckHelper.class);

	public LinkCheckHelper(ApplicationManager app) {
		this.app = app;
	}

	/**
	 * Check link for live
	 * 
	 * @param link
	 * @return
	 */
	public static boolean checkLinkForLive(String link) {
		HttpURLConnection urlConnection = null;

		try {
			URL url = new URL(link);
			urlConnection = (HttpURLConnection) url.openConnection();
			urlConnection.setRequestMethod("HEAD");
			urlConnection.setConnectTimeout(5000); // timeout after 5s if can't connect
			urlConnection.setReadTimeout(10000); // timeout after 10s if the page is too slow
			urlConnection.connect();

			String redirectLink = urlConnection.getHeaderField("Location");

			if (redirectLink != null && !link.equals(redirectLink)) {
				return checkLinkForLive(redirectLink);
			} else {
				return urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK;
			}
		} catch (Exception e) {
			return false;
		} finally {
			if (urlConnection != null) {
				urlConnection.disconnect();
			}
		}
	}

	/**
	 * Check an object
	 * 
	 * @param p_target
	 * @param p_atribute
	 * @param p_param
	 */
	public List<String> checkObject(String p_target, WebElement p_area, String p_atribute, String p_param) {
		List<WebElement> myList;
		List<String> errorLinks = new ArrayList<String>();
		if (p_area == null) {
			myList = app.getDriver().findElements(By.tagName(p_target));
		} else {
			myList = p_area.findElements(By.tagName(p_target));
		}

		for (int i = 0; i < myList.size(); i++) {
			if (p_param.equals("isLive")) {
				try {
					if (!checkLinkForLive(myList.get(i).getAttribute(p_atribute))) {
						String errorLink = null;
						if (checkLinkRequestStatus(myList.get(i).getAttribute(p_atribute)) > 400) {
							errorLink = myList.get(i).getText() + "  " + myList.get(i).getAttribute(p_atribute)
									+ " Status: " + checkLinkRequestStatus(myList.get(i).getAttribute(p_atribute));
						} else {
							errorLink = myList.get(i).getText() + "  " + myList.get(i).getAttribute(p_atribute)
									+ " Status: Timed out or loads too slow";
						}

						app.errors().set("Link error: <" + p_target + ">: " + errorLink);
						errorLinks.add(myList.get(i).getAttribute(p_atribute));
					}
				} catch (Exception e) {
				}
			}
			try {
				if (p_param.equals("isHttps")) {
					if (!myList.get(i).getAttribute(p_atribute).contains("https:")) {
						String linkNotHttps = myList.get(i).getText() + "  " + myList.get(i).getAttribute(p_atribute)
								+ " Status: doesht have https:";
						LOG.warn("Link error: <" + p_target + ">: " + linkNotHttps);
						errorLinks.add(myList.get(i).getAttribute(p_atribute));
						;
					}
				}
			} catch (Exception e) {
			}
		}
		return errorLinks;
	}

	/**
	 * Check links
	 */
	public List<String> checkLinks() {
		LOG.info("Check links on the page");

		return checkObject("a", null, "href", "isLive");
	}

	/**
	 * Check links
	 * 
	 * @param p_areas
	 * @return
	 */
	public List<String> checkLinks(WebElement[] p_areas) {
		List<String> errorLinks = new ArrayList<String>();
		for (WebElement area : p_areas) {
			LOG.info("Checking links in the area ", area);
			errorLinks.addAll(checkObject("a", area, "href", "isLive"));
		}
		return errorLinks;
	}

	/**
	 * Check images
	 * 
	 * @return List
	 */
	public List<String> checkImages() {
		LOG.info("Check images on the page");
		return checkObject("img", null, "src", "isLive");
	}

	/**
	 * Check images in the areas WebElement[]
	 * 
	 * @param p_areas
	 * @return
	 */
	public List<String> checkImages(WebElement[] p_areas) {
		List<String> errorLinks = new ArrayList<String>();
		for (WebElement area : p_areas) {
			LOG.info("Checking images in the area ", area);
			errorLinks.addAll(checkObject("img", area, "src", "isLive"));
		}
		return errorLinks;
	}

	/**
	 * Check links for is https
	 * 
	 * @return
	 */
	public List<String> checkForHttps() {
		LOG.info("Checking links on the page for https...");
		return checkObject("a", null, "href", "isHttps");

	}

	/**
	 * Check links for is https
	 * 
	 * @param p_areas
	 * @return
	 */
	public List<String> checkForHttps(WebElement[] p_areas) {
		List<String> errorLinks = new ArrayList<String>();
		for (WebElement area : p_areas) {
			LOG.info("Check links for https on the page ", area.toString());
			errorLinks.addAll(checkObject("a", area, "href", "isHttps"));
		}
		return errorLinks;
	}

	/**
	 * Check links for is https
	 * 
	 * @param p_area
	 * @return
	 */
	public List<String> checkForHttps(WebElement p_area) {
		WebElement[] area = { p_area };

		return checkForHttps(area);
	}

	/**
	 * Check links
	 * 
	 * @param p_linkURL
	 * @return error_code
	 */
	public int checkLinkRequestStatus(String p_linkURL) {
		int r_codeResponse;

		try {
			URL url = new URL(p_linkURL);

			HttpURLConnection link = (HttpURLConnection) url.openConnection();
			r_codeResponse = link.getResponseCode();

			return r_codeResponse;
		} catch (Exception e) {
			Integer linkErrorStatus = Integer.parseInt(e.toString());
			return linkErrorStatus;
		}
	}
}
